package com.caiyouxi.restrict.service;

import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.caiyouxi.common.service.BaseService;
import com.caiyouxi.common.util.Log;
import com.caiyouxi.finance.mapper.FinanceTradeDetailMapper;
import com.caiyouxi.finance.model.FinancePaymentDetail;
import com.caiyouxi.finance.model.FinanceTradeDetail;
import com.caiyouxi.goods.model.GoodsInfo;
import com.caiyouxi.order.mapper.OrderMapper;
import com.caiyouxi.order.model.OrderBean;
import com.caiyouxi.restrict.mapper.*;
import com.caiyouxi.restrict.model.*;
import com.caiyouxi.user.model.UserAccountBean;
import com.caiyouxi.user.model.UserProfile;
import com.caiyouxi.user.service.UserProfileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 业务限制条件检查service
 *
 * @author weichangyong
 * @create 2017-11-11 18:38
 **/
@Service
public class RestrictedConditionService extends BaseService {

    @Autowired
    private RestrictedConditionsMapper restrictedConditionsMapper;
    @Autowired
    private RestrictedByUserMapper restrictedByUserMapper;
    @Autowired
    private RestrictedByUserProfileMapper restrictedByUserProfileMapper;
    @Autowired
    private RestrictedByRechargeMapper restrictedByRechargeMapper;
    @Autowired
    private RestrictedByConsumeMapper restrictedByConsumeMapper;

    @Autowired
    private UserProfileService userProfileService;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private FinanceTradeDetailMapper financeTradeDetailMapper;

    /**
     * 业务限制条件检查
     * @param
     * @return
     */
    public boolean check_restrict(String target_type,String target_id,String target_action,int user_id,GoodsInfo goodsInfo)
    {

        Log.i("业务限制条件检查:+target_type:"+target_type+",target_id:"+target_id+",target_action:"+target_action+",user_id:"+user_id);
        //1、检查当前用户是否属于明确受限或允许的：查找 restricted_by_user：指定的受限用户列表-OK 表，
        // 根据给定的 target_type、target_id 、target_action 以及 user_id 字段查找是否有响应的记录。如果有
        // ，则返回该记录的 allowed 字段，即返回适用/不适用的结果。检查结束。
        RestrictedByUser search = new RestrictedByUser();
        search.setTarget_type(target_type);
        search.setTarget_id(target_id);
        search.setTarget_action(target_action);

        RestrictedByUser db_bean = get_restricted_by_user_pro(search);

        if(null!=db_bean && db_bean.getAllowed()==0)
        {
            //不允许
            Log.e("不允许的用户");
            return false;
        }

        //如果 restricted_by_user 表没有找到相关记录，则继续下面的检查。
        //检查 restricted_conditions：业务限制条件-OK 表，根据给定的 target_type、target_id 、target_action 查找对应的记录，如果没有找到结果，表示当前用户适用于该业务对象的限制条件，并返回。
        RestrictedConditions rc = new RestrictedConditions();
        rc.setTarget_type(target_type);
        rc.setTarget_action(target_action);
        rc.setTarget_id(target_id);
        RestrictedConditions res_db_bean = get_restricted_by_pro(rc);

        if(null!=res_db_bean && res_db_bean.getUser_profile_limited()>0 )
        {
            //检查 user_profile_limited 字段，如果该字段等于0，则跳过（表示没有限制）；如果为1，则根据 restricted_conditions.id 查找 restricted_by_user_profile：根据用户属性的限制条件-OK 表。
            boolean check_user_profile = check_user_profile(res_db_bean.getId(),user_id);
            if(!check_user_profile)
            {
                Log.e("条件规则检查，用户基本信息检查失败");
                return false;
            }
        }
        //检查 user_recharge_limited 字段。如果该字段等于0，则跳过；如果为1，则继续判断 restricted_by_recharge：根据用户充值情况的限制条件-OK 表。
        if(null!=res_db_bean && res_db_bean.getUser_recharge_limited()>0 )
        {
            boolean check_user_restricted_recharge = check_user_restricted_recharge(res_db_bean.getId(),user_id);
            if(!check_user_restricted_recharge)
            {
                Log.e("条件规则检查，用户充值记录检查失败");
                return false;
            }
        }

        //检查 user_consume_limited 字段，如果该字段等于0，则跳过；如果为1，则继续判断 restricted_by_consume：根据用户消费行为的限制条件-OK 表。
        if(null!=res_db_bean)
        {
            boolean check_user_consume_limited = check_user_consume_limited(res_db_bean.getId(),user_id,goodsInfo);
            if(!check_user_consume_limited)
            {
                Log.e("条件规则检查，用户消费记录失败");
                return false;
            }
        }

        Log.i("业务限制条件检查成功..");
        return true;

    }

    /**
     *  //检查 user_consume_limited 字段，如果该字段等于0，则跳过；如果为1，则继续判断 restricted_by_consume：根据用户消费行为的限制条件-OK 表。
     * @param id
     * @param user_id
     * @return
     */

    private boolean check_user_consume_limited(int id, int user_id,GoodsInfo goods) {

        RestrictedByConsume rbc = get_restricted_consume(id);
        if(null==rbc)
        {
            return true;
        }

        //消费起始时间限制：在该时间之后消费的（大于等于），具体到秒。如果为空，则不限起始时间。
        Date consume_begin_time = rbc.getConsume_begin_time();

        //消费结束时间限制：在该时间之前消费的（小于等于）。如果空，则不限结束时间。如果要限制具体某一天消费的，那么可以设定那一天的零点到当天的23:59:59
        Date consume_end_time = rbc.getConsume_end_time();


        FinanceTradeDetail search = new FinanceTradeDetail();
        search.setPayee(user_id);
        List<FinanceTradeDetail> trade_detail_list = financeTradeDetailMapper.get_user_consume_list(rbc);
        if(null==trade_detail_list)
        {
            Log.i("用户充值条件规则不满足！");
            return false;
        }

        //	消费金额大于等于该值。如果为0则表示不限制下限。为了简化，这里只针对 RMB 类型的货币的商品的消费金额。
        int consume_amount_from = rbc.getConsume_amount_from();
        //消费金额小于等于该值。如果为0则表示不限制上限。为了简化，这里只针对 RMB 类型的货币的商品的消费金额。
        int consume_amount_to = rbc.getConsume_amount_to();
        //计算订单总金额
        int sum_total = 0;
        for(FinanceTradeDetail o : trade_detail_list)
        {
            sum_total+=o.getFinished_amount();
        }
        if(consume_amount_from>0 && sum_total< consume_amount_from)
        {
            Log.i("消费金额小于设定值");
            return false;
        }
        if(consume_amount_to>0 && sum_total>consume_amount_to)
        {
            Log.i("消费金额大于设定值");
            return false;
        }
        //未购买过指定品类的，可多个用|分隔。如果该字段中和 purchased_categories 有冲突，则以该字段为准。即：如果purchased_categories=10|20，而 purchased_categories 中也包含 10，则以未购买过10 的优先。
        //代码中很好判断，直接将 not_purchased_categories 字段包含的值，从 purchased_categories 中排除掉，然后再去写 sql。下同。

        String not_purchased_categories = rbc.getNot_purchased_categories();

        if(null!=not_purchased_categories )
        {
            Log.i("已购买过此商品品类，失败");
            return false;
        }

        //购买过指定品类的，可多个用|分隔。
        String purchased_categories = rbc.getPurchased_categories();

        //未购买过指定的商品的，可多个用|分隔
        String not_purchased_goods = rbc.getNot_purchased_goods();

        //查询用户购买的订单
        OrderBean ob = new OrderBean();
        ob.setBuyer_user_id(user_id);
        ob.setStatus("COMPLETED");
        List<OrderBean> user_order_list = orderMapper.get_order_by_bean(ob);
        String goods_category_ids = "";
        String goods_ids="";
        if(null!=user_order_list)
        {
            for(OrderBean o:user_order_list)
            {
                goods_category_ids+=o.getGoods_category_id()+",";
                goods_ids +=o.getGoods_id()+",";
            }
        }

        //购买过指定的商品的，可多个用|分隔。和下面这两个字段可以同时为空，但是不能同时不为空。如果有数据有问题，这两个字段都不为空，则只判断该字段。
        String purchased_goods = rbc.getPurchased_goods();

        if(null!=not_purchased_categories && goods_category_ids.indexOf(goods.getCategory_id())!=-1) {
            Log.i("已购买过此商品品类，失败");
            return false;
        }
        if(null!= purchased_categories && goods_category_ids.indexOf(goods.getCategory_id())==-1)
        {
            Log.i("未购买过此商品品类，失败");
            return false;
        }
        if(null!=not_purchased_goods && goods_ids.indexOf(String.valueOf(goods.getId()))!=-1)
        {
            Log.i("已购买过此商品，失败");
            return false;
        }
        if(null!=purchased_goods && goods_ids.indexOf(String.valueOf(goods.getId()))==-1)
        {
            Log.i("未购买过此商品，失败");
            return false;
        }

        //检查使用过的支付方式

        Map<String,Object> map = new HashMap<String,Object>();
        map.put("user_id",user_id);
        map.put("consume_begin_time",consume_begin_time);
        map.put("consume_end_time",consume_end_time);

        //未使用过的支付方式。可多选使用|分隔。
        String not_used_payment_types = rbc.getNot_used_payment_types();
        //使用过的支付方式类型限制。可多选使用|分隔。ALIPAY、WECHAT、以及余额和虚拟币支付（如果系统设置了的话）。 如果该值为空，则表示任意支付方式。
        String used_payment_types = rbc.getUsed_payment_types();
        List<FinancePaymentDetail>  user_payment_list = financeTradeDetailMapper.get_user_payment(map);
        boolean not_user_payment_temp=true;
        boolean user_payment_temp=true;
        if(null!=user_payment_list)
        {
            for(FinancePaymentDetail fpd:user_payment_list)
            {
                if(null!=not_used_payment_types && not_used_payment_types.indexOf(fpd.getPayment_type())!=-1)
                {
                    not_user_payment_temp = false;
                }
                if(null!=used_payment_types && used_payment_types.indexOf(fpd.getPayment_type())==-1)
                {
                    user_payment_temp = false;
                }
            }
        }
        if(!not_user_payment_temp)
        {
            Log.i("已使用过配置的支付方式，失败...");
            return false;
        }
        if(!user_payment_temp)
        {
            Log.i("未使用过配置的支付方式，失败...");
            return false;
        }
        //检查券
        //使用过券或使用具体哪些批次的券。
        // 如果为空，则表示不做限制；
        //如果为 ALL 则表示使用过任意的券即符合条件；
        //除了上面两种情况之外，表示限定使用过指定的券，可多选用|分隔。
        String used_coupons = rbc.getUsed_coupons();



        /*
        未使用过券或未使用过哪些具体批次的券。
        如果为空，则表示不做限制；
        如果为 ALL 则表示未使用过任意的券。如果 used_coupons 也为 ALL，则 used_coupons 字段无效；
         */
        String not_used_coupons = rbc.getNot_used_coupons();
        map.put("payment_type","COUPON");
        List<FinancePaymentDetail>  user_coupons_list = financeTradeDetailMapper.get_user_payment(map);
        if(not_used_coupons!=null && "ALL".equals(not_purchased_categories))
        {
            if(null!=user_coupons_list||user_coupons_list.size()>0)
            {
                Log.i("已使用过券的记录，失败");
                return false;
            }
        }
        if(not_used_coupons!=null && !"ALL".equals(not_purchased_categories))
        {
            for(FinancePaymentDetail ff:user_coupons_list)
            {
                if(null!=not_used_coupons && not_used_coupons.indexOf(ff.getPayment_detail())!=-1)
                {
                    Log.i("已使用过券的记录，失败");
                    return false;
                }
            }
        }
        if(used_coupons!=null && "ALL".equals(used_coupons))
        {
            if(null==user_coupons_list||user_coupons_list.size()==0)
            {
                Log.i("未使用过券的记录，失败");
                return false;
            }
        }
        if(used_coupons!=null && !"ALL".equals(used_coupons))
        {
            for(FinancePaymentDetail ffp :user_coupons_list)
            {
                if(null!=used_coupons && used_coupons.indexOf(ffp.getPayment_detail())!=-1)
                {
                    Log.i("未使用过此券的记录，失败");
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 检查 user_recharge_limited 字段。如果该字段等于0，则跳过；如果为1，则继续判断 restricted_by_recharge：根据用户充值情况的限制条件-OK 表。
     * @param id
     * @param user_id
     * @return
     */
    private boolean check_user_restricted_recharge(int id, int user_id) {
        RestrictedByRecharge rbr = get_restricted_recharge(id);

        //充值起始时间限制：在该时间之后充值的（大于等于），具体到秒。如果为空，则不限起始时间。
//        Date recharge_begin_time = rbr.getRecharge_begin_time();
        //	充值结束时间限制：在该时间之前充值的（小于等于）。如果空，则不限结束时间。如果要限制具体某一天充值的，那么可以设定那一天的零点到当天的23:59:59
//        Date recharge_end_time = rbr.getRecharge_end_time();

        //充值金额大于等于该值。如果为0则表示不限制下限。
       int recharge_amout_from = rbr.getRecharge_amout_from();
        //充值金额小于等于该值。如果为0则表示不限制上限。
        int recharge_amount_to = rbr.getRecharge_amount_to();
        //第三方支付方式类型限制。可多选使用|分隔。目前已经有的是：ALIPAY、WECHAT。 如果该值为空，则表示任意支付方式。
        String payment_gateway_types = rbr.getPayment_types();

        rbr.setUser_id(user_id);
        List<OrderBean> user_order_list = orderMapper.get_order_by_user_condetion(rbr);
        if(null==user_order_list)
        {
            Log.i("用户充值条件规则不满足！");
            return false;
        }
        //计算订单总金额
        int sum_total = 0;
        boolean payment_type_temp = false;
        for(OrderBean o : user_order_list)
        {
            sum_total+=o.getTotal_amount();
            if(!StringUtils.isEmpty(payment_gateway_types))
            {
                if(payment_gateway_types.indexOf(o.getPayment_type())!=-1)
                {
                    payment_type_temp = true;
                }
            }
        }
        if(recharge_amout_from>0 && sum_total< recharge_amout_from)
        {
            Log.i("充值金额小于设定值");
            return false;
        }
        if(recharge_amount_to>0 && sum_total>recharge_amount_to)
        {
            Log.i("充值金额大于设定值");
            return false;
        }
        //检查支付方式
        if(!payment_type_temp)
        {
            Log.i("第三方支付方式类型限制");
            return false;
        }
        return true;
    }

    /**
     * 检查 user_recharge_limited 字段。如果该字段等于0，则跳过；如果为1，则继续判断 restricted_by_recharge：根据用户充值情况的限制条件-OK 表。
     * @param condition_id
     * @return
     */
    private RestrictedByConsume get_restricted_consume(int condition_id)
    {

        String redis_key = "RestrictedByConsume_"+condition_id;
        Log.d("search redis..."+redis_key);
        RestrictedByConsume db_bean = (RestrictedByConsume) redisService.get(redis_key);
        if (null == db_bean){
            Log.d("search db...");
            db_bean  = restrictedByConsumeMapper.select_restricted_by_consume(condition_id);
            redisService.set(redis_key,db_bean);
        }
        return  db_bean;

    }

    /**
     * 检查 user_recharge_limited 字段。如果该字段等于0，则跳过；如果为1，则继续判断 restricted_by_recharge：根据用户充值情况的限制条件-OK 表。
     * @param condition_id
     * @return
     */
    private RestrictedByRecharge get_restricted_recharge(int condition_id)
    {

        String redis_key = "RestrictedByRecharge"+condition_id;
        Log.d("search redis..."+redis_key);
        RestrictedByRecharge db_bean = (RestrictedByRecharge) redisService.get("redis_key_id" + redis_key);
        if (null == db_bean){
            Log.d("search db...");
            db_bean  = restrictedByRechargeMapper.select_restricted_by_recharge(condition_id);
            redisService.set("redis_key_id" + redis_key,db_bean);
        }
        return  db_bean;

    }

    /**
     *
     *   //检查 restricted_conditions：业务限制条件-OK 表，根据给定的 target_type、target_id 、target_action 查找对应的记录，如果没有找到结果，表示当前用户适用于该业务对象的限制条件，并返回。
     * @return
     */
    private boolean check_user_profile(int condition_id,int user_id)
    {
        RestrictedByUserProfile rbp = select_restricted_by_user_profile(condition_id);
        if(null==rbp)
        {
            return true;
        }
       //分别检验用户相关
        UserProfile user = userProfileService.get_user_by_id(user_id);
        String reg_log = user.getReg_log();
        JSONObject obj = JSONObject.parseObject(reg_log);
        //获取用户相关信息
        Date reg_date = obj.getDate("reg_time");

        //用户注册的设备信息
        JSONObject device_obj = obj.getJSONObject("device");
        String device_type = device_obj.getString("device_type");
        String appFrom = obj.getString("appFrom");
        String channel = obj.getString("channel");
        String promos = obj.getString("promos");
        //注册地址
        String reg_location = obj.getString("reg_location");

        //最后登录信息
        String last_login_log = user.getLast_login_log();

        JSONObject last_login_obj = JSONObject.parseObject(last_login_log);
        //最后登录时间
        Date last_login_time = null;
        if(null!=last_login_obj) {
            last_login_time = last_login_obj.getDate("login_time");
        }

        System.out.println("注册时间" + reg_date + "====" + rbp.getRegister_begin_time() + "====" + rbp.getRegister_end_time());
        //检验注册开始时间
        if(null!=rbp.getRegister_begin_time()&& reg_date.getTime() < rbp.getRegister_begin_time().getTime())
        {
            Log.i("注册时间小于开始时间..");
            return false;
        }
        //检验注册结束时间
        if(null!=rbp.getRegister_end_time()&& reg_date.getTime() > rbp.getRegister_end_time().getTime())
        {
            Log.i("注册时间大于结束时间..");
            return false;
        }
        //检验用户注册时的设备类型
        if(null!=rbp.getRegister_device_platforms() && !rbp.getRegister_device_platforms().equals(device_type))
        {
            Log.i("用户注册时的设备类型限制");
            return false;
        }
        //检验用户注册来源，比如：JINGJING|TCB|SDK
        if(null!=rbp.getRegister_apps()&& rbp.getRegister_apps().indexOf(appFrom)== -1)
        {
            Log.i("该用户类型不允许");
            return false;
        }
        //不允许的渠道来源。优先级比 allowed_source_channels 高。
        if(null!=rbp.getDenied_source_channels() && rbp.getDenied_source_channels().indexOf(channel)!= -1)
        {
            Log.i("该用户渠道不允许");
            return false;
        }
        //	不允许的推广码，优先级比 allowed_promos 高。
        if(null!=rbp.getDenied_promos() && rbp.getDenied_promos().indexOf(promos)!= -1)
        {
            Log.i("不允许的推广码");
            return false;
        }
        //不允许的注册地。优先级比 allowed_register_locations 高
        if(null!=rbp.getDenied_register_locations() && rbp.getDenied_register_locations().indexOf(reg_location)!= -1)
        {
            Log.i("不允许的注册地");
            return false;
        }

        //允许的登录账号来源。可以多选用|分隔。



        //是否只允许绑定过手机的。0-不限制；1-限制，只有绑定过手机的用户才满足条件
        if(null!=rbp.getBind_phone()&& rbp.getRealname_verified()==1 )
        {
            UserAccountBean uab = userProfileService.get_user_account_by_source(user_id,"PHONE");
            if(null==uab)
            {
                Log.i("用户未绑定手机");
                return false;
            }
        }


        //是否只允许实名认证过的。0-不限制；1-限制，
        if(null!=rbp.getRealname_verified()&& rbp.getRealname_verified()==1 && "VERIFIED,VERIFYING ".indexOf(user.getAuth_status())==-1)
        {
            Log.i("只允许实名认证过的.");
            return false;
        }

        //是否只允许指定日期之后有登录行为的用户。如果该字段为空，则表示不限制。
        if(null!=last_login_time&&null!=rbp.getLogin_last_time()&& last_login_time.getTime() < rbp.getLogin_last_time().getTime())
        {
            Log.i("最后登录时间受限制..");
            return false;
        }

        return true;
    }

    /**
     * 检查当前否属于明确受限或允许的：
     * @param
     * @return
     */
    private RestrictedByUserProfile select_restricted_by_user_profile(int condition_id) {

        String redis_key = "RestrictedByUserProfile_"+condition_id;
        Log.d("search redis..."+redis_key);
        //RestrictedByUserProfile db_bean = (RestrictedByUserProfile) redisService.get(redis_key);
        RestrictedByUserProfile db_bean = null;
        if (null == db_bean){
            Log.d("search db...");
            db_bean  = restrictedByUserProfileMapper.select_restricted_by_user_profile(condition_id);
            redisService.set(redis_key,db_bean);
        }
        return  db_bean;
    }
    /**
     * 检查当前否属于明确受限或允许的：
     * @param bean
     * @return
     */
    private RestrictedConditions get_restricted_by_pro(RestrictedConditions bean) {

        String redis_key = "RestrictedConditions_"+bean.getTarget_type()+"_"+bean.getTarget_id()+"_"+bean.getTarget_action();
        Log.d("search redis...");
        //RestrictedConditions db_bean = (RestrictedConditions) redisService.get(redis_key);
        RestrictedConditions db_bean = null;
        if (null == db_bean){
            Log.d("search db...");
            db_bean  = restrictedConditionsMapper.get_restricted_by_pro(bean);
            redisService.set(redis_key,db_bean);
        }
        return  db_bean;
    }
    /**
     * 检查当前用户是否属于明确受限或允许的：
     * @param bean
     * @return
     */
    private RestrictedByUser get_restricted_by_user_pro(RestrictedByUser bean) {

        String redis_key = "RestrictedByUser_"+bean.getTarget_type()+"_"+bean.getTarget_id()+"_"+bean.getTarget_action();
        Log.d("search redis...");
      //  RestrictedByUser db_bean = (RestrictedByUser) redisService.get(redis_key);
        RestrictedByUser db_bean = null;
        if (null == db_bean){
            Log.d("search db...");
            db_bean  = restrictedByUserMapper.get_restricted_by_user_pro(bean);
            redisService.set(redis_key,db_bean);
        }
        return  db_bean;
    }
}
